package org.openkanban.client.ui.board;

import org.openkanban.client.cometd.CometClient;
import org.openkanban.client.cometd.SubscribeCallback;
import org.openkanban.client.login.LogIn;
import org.openkanban.client.ui.presenter.CreateBoardRequestCallback;
import org.openkanban.client.ui.presenter.PreparedRequest;
import org.openkanban.client.ui.presenter.SwitchBoardRequestCallback;
import org.openkanban.client.ui.presenter.UpdateBoardRequestCallback;
import org.openkanban.client.util.RootPanel;
import org.openkanban.shared.dto.BoardDto;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.json.client.JSONObject;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.AnimationEffect;
import com.smartgwt.client.types.BkgndRepeat;
import com.smartgwt.client.util.JSON;
import com.smartgwt.client.widgets.AnimationCallback;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.events.DoubleClickEvent;
import com.smartgwt.client.widgets.events.DoubleClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
import com.smartgwt.client.widgets.form.fields.events.KeyPressEvent;
import com.smartgwt.client.widgets.form.fields.events.KeyPressHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.Layout;
import com.smartgwt.client.widgets.layout.VLayout;

/**
 * GUI Element for the BoardView
 */
public class BoardView extends VLayout implements BoardComposite {
    private static final int BOARD_NAME_MIN_WIDTH = 150;
    private Label currentBoardNameLabel;
    private DynamicForm currentBoardNameForm;
    private TextItem currentBoardNameTextItem;

    private IButton newActivityButton;
    private IButton newKanbanButton;
    private IButton nextBoardButton;
    private IButton prioBoardButton;

    private HLayout boardHeaderHLayout;
    private Layout boardHeaderLeftLayout;
    private Layout boardHeaderMiddleLayout;
    private HLayout boardHeaderRightHLayout;
    private Layout boardHeaderSwitchLayout;
    private Layout border1;

    private HLayout greyBackground;
    private HLayout kanbanHLayout;
    private VLayout kanbanLayout;

    private WhiteBoardView whiteBoardView;
    private KanbanEditView kanbanEditView;

    private RequestCallback switchBoardRequestCallback;
    private boolean footerWasOpenFlag;

    private CometClient cometClient;

    public BoardView() {
	cometClient = RootPanel.main.getCometClient();

	setBackgroundImage("bg_grey3.png");
	setBackgroundRepeat(BkgndRepeat.REPEAT);

	whiteBoardView = new WhiteBoardView();

	switchBoardRequestCallback = new SwitchBoardRequestCallback(this);

	newActivityButton = new OpenKanbanButton("+ activity");
	newActivityButton.addClickHandler(new ClickHandler() {
	    @Override
	    public void onClick(ClickEvent event) {
		newActivityButton.setDisabled(true);
		ActivityView activityView = new ActivityView(whiteBoardView.getBoardDto().getBoardId());
		whiteBoardView.addActivity(activityView);
	    }
	});

	newKanbanButton = new OpenKanbanButton("+ kanban");
	newKanbanButton.setVisible(false);
	newKanbanButton.addClickHandler(new ClickHandler() {
	    @Override
	    public void onClick(ClickEvent event) {
		RootPanel.activateEditKanbanMode(true);
	    }
	});

	prioBoardButton = new OpenKanbanButton("<<");
	prioBoardButton.setWidth(40);
	prioBoardButton.addClickHandler(new ClickHandler() {
	    @Override
	    public void onClick(ClickEvent event) {
		PreparedRequest prepReq = new PreparedRequest("board", whiteBoardView.getBoardDto().getBoardId().toString() + "/"
			+ LogIn.getUserDto().getUserId().toString() + "/backward");
		prepReq.sendAsyncRequest(switchBoardRequestCallback);
	    }
	});

	nextBoardButton = new OpenKanbanButton(">>");
	nextBoardButton.setWidth(40);
	nextBoardButton.addClickHandler(new ClickHandler() {
	    @Override
	    public void onClick(ClickEvent event) {
		PreparedRequest prepReq = new PreparedRequest("board", whiteBoardView.getBoardDto().getBoardId().toString() + "/"
			+ LogIn.getUserDto().getUserId().toString() + "/forward");
		prepReq.sendAsyncRequest(switchBoardRequestCallback);
	    }
	});

	boardHeaderHLayout = new HLayout();
	boardHeaderHLayout.setHeight(40);
	boardHeaderHLayout.setVisible(false);

	currentBoardNameLabel = new Label();
	currentBoardNameLabel.setWrap(false);
	currentBoardNameLabel.setStyleName("boardNameLabel");
	currentBoardNameLabel.setMinWidth(BOARD_NAME_MIN_WIDTH);
	currentBoardNameLabel.setAlign(Alignment.CENTER);
	currentBoardNameLabel.addDoubleClickHandler(boardNameLabelDoubleClickHandler());

	currentBoardNameTextItem = new TextItem();
	currentBoardNameTextItem.setShowTitle(false);
	currentBoardNameTextItem.setHeight(30);
	currentBoardNameTextItem.setWidth(BOARD_NAME_MIN_WIDTH);
	currentBoardNameTextItem.setTextBoxStyle("boardNameTextItem");
	currentBoardNameTextItem.setShowFocused(true);
	currentBoardNameTextItem.addKeyPressHandler(updateBoardNameKeyPressedHandler());
	currentBoardNameTextItem.addBlurHandler(updateBoardNameBlurHandler());

	currentBoardNameForm = new DynamicForm();
	currentBoardNameForm.setFields(currentBoardNameTextItem);

	// BoardHeader
	Layout leftMargin = new Layout();
	Layout rightMargin = new Layout();
	leftMargin.setWidth(10);
	rightMargin.setWidth(10);

	boardHeaderLeftLayout = new Layout();
	boardHeaderLeftLayout.setAutoWidth();
	boardHeaderLeftLayout.setBackgroundImage("boardheader/boardheader_left.png");
	boardHeaderLeftLayout.setBackgroundRepeat(BkgndRepeat.REPEAT_X);
	boardHeaderLeftLayout.addMember(leftMargin);
	boardHeaderLeftLayout.addMember(currentBoardNameLabel);

	boardHeaderMiddleLayout = new Layout();
	boardHeaderMiddleLayout.setWidth(55);
	boardHeaderMiddleLayout.setBackgroundImage("boardheader/boardheader_middle.png");

	boardHeaderRightHLayout = new HLayout();
	boardHeaderRightHLayout.setWidth("*");
	boardHeaderRightHLayout.setStyleName("boardHeaderLayout");
	boardHeaderRightHLayout.setBackgroundImage("boardheader/boardheader_right.png");
	boardHeaderRightHLayout.setBackgroundRepeat(BkgndRepeat.REPEAT_X);
	boardHeaderRightHLayout.addMember(newActivityButton);
	boardHeaderRightHLayout.addMember(newKanbanButton);

	boardHeaderSwitchLayout = new Layout();
	boardHeaderSwitchLayout.setStyleName("boardHeaderLayout");
	boardHeaderSwitchLayout.setAutoWidth();
	boardHeaderSwitchLayout.setBackgroundImage("boardheader/boardheader_right.png");
	boardHeaderSwitchLayout.setBackgroundRepeat(BkgndRepeat.REPEAT_X);
	boardHeaderSwitchLayout.addMember(prioBoardButton);
	boardHeaderSwitchLayout.addMember(nextBoardButton);
	boardHeaderSwitchLayout.addMember(rightMargin);

	boardHeaderHLayout.setHeight(57);
	boardHeaderHLayout.addMember(boardHeaderLeftLayout);
	boardHeaderHLayout.addMember(boardHeaderMiddleLayout);
	boardHeaderHLayout.addMember(boardHeaderRightHLayout);
	boardHeaderHLayout.addMember(boardHeaderSwitchLayout);

	// KanbanEditMode
	greyBackground = new HLayout();
	greyBackground.setBackgroundColor("#000000");
	greyBackground.setOpacity(70);
	greyBackground.setWidth100();
	greyBackground.setHeight100();
	greyBackground.setVisible(false);

	kanbanHLayout = new HLayout();
	kanbanHLayout.setWidth100();
	kanbanHLayout.setAlign(Alignment.CENTER);

	kanbanEditView = new KanbanEditView();
	Layout borderL = new Layout();
	borderL.setWidth("*");
	Layout borderR = new Layout();
	borderR.setWidth("*");

	kanbanHLayout.addMember(borderL);
	kanbanHLayout.addMember(kanbanEditView);
	kanbanHLayout.addMember(borderR);

	border1 = new Layout();
	border1.setHeight(63);

	kanbanLayout = new VLayout();
	kanbanLayout.setWidth100();
	kanbanLayout.setHeight100();
	kanbanLayout.setAlign(Alignment.CENTER);
	kanbanLayout.setVisible(false);

	kanbanLayout.addMember(border1);
	kanbanLayout.addMember(kanbanHLayout);

	addMember(boardHeaderHLayout);
	addMember(whiteBoardView);

	addChild(greyBackground);
	addChild(kanbanLayout);
    }

    @Override
    public void switchBoard(Long boardId) {
	subscribe();
    }

    public void subscribe() {
	cometClient.subscribe("/board/" + whiteBoardView.getBoardDto().getBoardId().toString() + "/namechanged", new SubscribeCallback() {
	    @Override
	    public void execute(JavaScriptObject jso) {
		JSONObject jsonObject = new JSONObject(jso);
		JSONObject jsonDataObject = jsonObject.get("data").isObject();

		String boardName = jsonDataObject.get("boardName").isString().stringValue();
		currentBoardNameLabel.setContents(boardName);
	    }
	});
    }

    public void publish() {
	cometClient.publish("/board/" + whiteBoardView.getBoardDto().getBoardId().toString() + "/namechanged",
		JSON.decode("{ \"boardName\": \"" + whiteBoardView.getBoardDto().getBoardName() + "\" }"));
    }

    private KeyPressHandler updateBoardNameKeyPressedHandler() {
	return new KeyPressHandler() {
	    @Override
	    public void onKeyPress(KeyPressEvent event) {
		if ("Enter".equals(event.getKeyName())) {
		    updateBoardName(currentBoardNameTextItem.getValueAsString());
		}
	    }
	};
    }

    private BlurHandler updateBoardNameBlurHandler() {
	return new BlurHandler() {
	    @Override
	    public void onBlur(BlurEvent event) {
		updateBoardName(currentBoardNameTextItem.getValueAsString());
	    }
	};
    }

    public void updateBoardName(String boardName) {
	currentBoardNameLabel.setContents(boardName);
	whiteBoardView.getBoardDto().setBoardName(boardName);

	showCurrentBoardNameLabel();

	PreparedRequest prepReq = new PreparedRequest("board", "update", whiteBoardView.getBoardDto());
	prepReq.sendAsyncRequest(new UpdateBoardRequestCallback());
    }

    public void createBoard(String boardName) {
	currentBoardNameLabel.setContents(boardName);
	BoardDto newBoardDto = new BoardDto();
	newBoardDto.setBoardName(boardName);

	showCurrentBoardNameLabel();

	PreparedRequest prepReq = new PreparedRequest("board", "create", newBoardDto);
	prepReq.sendAsyncRequest(new CreateBoardRequestCallback());
    }

    private DoubleClickHandler boardNameLabelDoubleClickHandler() {
	return new DoubleClickHandler() {
	    @Override
	    public void onDoubleClick(DoubleClickEvent event) {
		currentBoardNameTextItem.setValue(currentBoardNameLabel.getContents());

		showCurrentBoardNameForm();
	    }
	};
    }

    public void showCurrentBoardNameForm() {
	if (!boardHeaderLeftLayout.contains(currentBoardNameForm)) {
	    boardHeaderLeftLayout.removeMember(currentBoardNameLabel);
	    boardHeaderLeftLayout.addMember(currentBoardNameForm, 1);
	}
    }

    public void showCurrentBoardNameLabel() {
	if (!boardHeaderLeftLayout.contains(currentBoardNameLabel)) {
	    boardHeaderLeftLayout.removeMember(currentBoardNameForm);
	    boardHeaderLeftLayout.addMember(currentBoardNameLabel, 1);
	}
    }

    public void setKanbanEditMode(boolean isEdit) {
	if (isEdit) {
	    kanbanEditView.clear();
	    showEditKanbanMode();
	} else {
	    hideEditKanbanMode();
	}
    }

    public void setKanbanEditMode(boolean isEdit, KanbanView kanbanView) {
	if (isEdit) {
	    kanbanEditView.loadKanban(kanbanView);
	}
	showEditKanbanMode();
    }

    private void hideEditKanbanMode() {
	if (!footerWasOpenFlag) {
	    kanbanLayout.animateHide(AnimationEffect.FLY, new AnimationCallback() {
		@Override
		public void execute(boolean earlyFinish) {
		    RootPanel.main.getFooter().getFooterPanel().closeFooter(new AnimationCallback() {
			@Override
			public void execute(boolean earlyFinish) {
			    greyBackground.animateHide(AnimationEffect.FADE, null, 500);
			}
		    });
		}
	    }, 500);
	} else {
	    kanbanLayout.animateHide(AnimationEffect.FLY, new AnimationCallback() {
		@Override
		public void execute(boolean earlyFinish) {
		    greyBackground.animateHide(AnimationEffect.FADE, null, 500);
		}
	    }, 500);
	}
    }

    private void showEditKanbanMode() {
	footerWasOpenFlag = RootPanel.main.getFooter().getFooterPanel().isOpened();
	kanbanEditView.setParentActivityId(whiteBoardView.getFirstActicityDto().getActivityId());
	if (!footerWasOpenFlag) {
	    RootPanel.main.getFooter().getFooterPanel().openFooter(new AnimationCallback() {
		@Override
		public void execute(boolean earlyFinish) {
		    greyBackground.animateShow(AnimationEffect.FADE, new AnimationCallback() {
			@Override
			public void execute(boolean earlyFinish) {
			    kanbanLayout.animateShow(AnimationEffect.FADE, null, 500);
			};
		    }, 500);
		}
	    });
	} else {
	    greyBackground.animateShow(AnimationEffect.FADE, new AnimationCallback() {
		@Override
		public void execute(boolean earlyFinish) {
		    kanbanLayout.animateShow(AnimationEffect.FADE, null, 500);
		};
	    }, 500);
	}
    }

    public void enableNewActivityButton() {
	newActivityButton.setDisabled(false);
    }

    public void showNewKanbanButton() {
	if (!newKanbanButton.isVisible()) {
	    newKanbanButton.setVisible(true);
	}
    }

    public void hideNewKanbanButton() {
	newKanbanButton.setVisible(false);
    }

    public Label getCurrentBoardNameLabel() {
	return currentBoardNameLabel;
    }

    public HLayout getBoardHeaderHLayout() {
	return boardHeaderHLayout;
    }

    public WhiteBoardView getWhiteBoardView() {
	return whiteBoardView;
    }

    public IButton getNewKanbanButton() {
	return newKanbanButton;
    }

    public void showNewActivityButton() {
	newActivityButton.show();
    }

}
